﻿#ifndef _C_RTMP_SERVER_H
#define _C_RTMP_SERVER_H

#include "../../../includes/network/networkframemanager.h"
#include "../../../includes/network/ctcpsocketserver.h"
#include "rtmpchunk.h"
#include "amf.h"

#include <QObject>
#include <QThread>
#include <QTcpSocket>
#include <QTcpServer>
#include <QMutex>
#include <QTime>

/**
 * @brief 使用说明
 *
 * 1.首先安装ffmpeg
 * 2.启动rtmpserver
 * 3.ffmpeg -f gdigrab -video_size 640x480 -framerate 15 -i desktop -vcodec libx264 -f flv rtmp://127.0.0.1/live/mystream
 * 4.打开vlc,打开串流，输入：rtmp://127.0.0.1:1935/live/mystream
 */

class cRtmpServer;
class cRtmpClient;

class cRtmpServer : public QTcpServer
{
    Q_OBJECT

public:      
    explicit cRtmpServer(QObject *parent = nullptr);
    ~cRtmpServer();

    /// 打开一个指定端口的服务器
    Q_INVOKABLE bool OpenServer(int port=1935);
    /// 关闭服务器
    Q_INVOKABLE void CloseServer(void);
    /// 添加到一个组中
    Q_INVOKABLE bool addSession(QString sessionName,cRtmpClient * pclient);
    /// 从指定组里清除指定客户端
    Q_INVOKABLE bool delSession(QString sessionName,cRtmpClient *client);
    /// 检测指定名称的发布者是否存在
    Q_INVOKABLE bool HasPublisher(QString sessionName);
    /// 得到指定组里所有的客户端
    Q_INVOKABLE QList<cRtmpClient *> getSession(QString sessionName);
    /// 锁闭所有客户端
    Q_INVOKABLE void locksessions(void) { m_clientmutex.lock(); }
    /// 解锁所有客户端
    Q_INVOKABLE void unlocksessions(void) { m_clientmutex.unlock(); }
    void SetAvcSequenceHeader(QByteArray avcSequenceHeader, uint32_t avcSequenceHeaderSize);
    void SendMediaData(QString sessionName,uint8_t type, uint64_t timestamp,
                       QByteArray data,int datasize);
    void SetMetaData(AmfObjects metaData);
    void SendMetaData(QString sessionName,AmfObjects& metaData);
    inline void setmaxchunksize(uint32_t size) { max_chunk_size_ = size; }
    inline uint32_t getmaxchunksize(void) { return max_chunk_size_; }
    inline void SetGopCache(QString sessionName,uint32_t cacheLen)
    {
        m_gop_params[sessionName].max_gop_cache_len_ = cacheLen;
    }

signals:
    /// 日志消息
    void sockLog(QString log);

private:
    /// 从系统中清除所有客户端
    void deleteAllClients(void);
    /// 从系统中清除指定客户端
    void deleteTheClient(qintptr conn);
    /// 覆盖已获取多线程
    void incomingConnection(qintptr socketDescriptor);
    /// 日志消息
    void showLog(QString log);
    cRtmpClient * getClient(qintptr socketDescriptor);

private slots:
    void displayError(QAbstractSocket::SocketError socketError);
    void sockConnectSlot(qintptr conn);
    void sockDisConnectSlot(qintptr conn);
    /// 处理网络二进制消息
    void sockBinMessageSlot(qintptr conn,QByteArray &data);
    /// 日志消息
    void sockLogSlot(QString log);
    /// 处理心跳消息
    void handleRtmpServerHeartTimeOut(void);
    void SendGop(QString sessionName,cRtmpClient* conn);
    void SaveGop(QString sessionName,uint8_t type, uint64_t timestamp, QByteArray data, uint32_t size);

private:
    QMutex m_clientmutex;
    QHash<qintptr, cRtmpClient *> tcpClients;                              /**< 管理连接的map */
    QHash<QString, QList<cRtmpClient *>> sessionClients;

    QTimer m_RtmpServerHeartTimeOutTimer;                                  /**< 处理心跳的定时器 */
    QByteArray avc_sequence_header_;
    uint32_t avc_sequence_header_size_;
    AmfObjects meta_data_;
    uint32_t max_chunk_size_;

    struct AVFrame
    {
        AVFrame()
            : type(0),timestamp(0),size(0) {}
        AVFrame(uint8_t t,uint64_t tt,uint32_t s,QByteArray d)
            : type(t),timestamp(tt),size(s),data(d) {}

        uint8_t  type;
        uint64_t timestamp;
        uint32_t size;
        QByteArray data;
    };
    QHash<QString,QMap<uint64_t, QList<AVFrame>>> gop_cache_;

    struct tagGop
    {
        tagGop()
            : max_gop_cache_len_(0),gop_index_(0) {}
        tagGop(uint32_t mgcl,uint64_t gi)
            : max_gop_cache_len_(mgcl),gop_index_(gi) {}

        uint32_t max_gop_cache_len_;
        uint64_t gop_index_;
    };
    QHash<QString,tagGop> m_gop_params;
};

#endif
